<script lang="ts" setup>
import { ref } from 'vue'

const originalUrl = ref('')
const encodedUrl = ref('')
const decodedUrl = ref('')
const errorMessage = ref('')
const isSuccess = ref(false)
const encodeType = ref('component') // component, full
const encodeLevel = ref(1) // 1, 2, 3 (编码次数)

// URL编码
function encodeUrl() {
  try {
    if (!originalUrl.value.trim()) {
      errorMessage.value = '请输入要编码的URL'
      isSuccess.value = false
      return
    }
    
    let result = originalUrl.value
    
    // 根据编码类型选择方法
    for (let i = 0; i < encodeLevel.value; i++) {
      if (encodeType.value === 'component') {
        result = encodeURIComponent(result)
      } else {
        result = encodeURI(result)
      }
    }
    
    encodedUrl.value = result
    errorMessage.value = `URL编码成功 ✓ (${encodeType.value === 'component' ? 'Component' : 'Full'}, ${encodeLevel.value}次)`
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `URL编码失败: ${(error as Error).message}`
    isSuccess.value = false
    encodedUrl.value = ''
  }
}

// URL解码
function decodeUrl() {
  try {
    if (!encodedUrl.value.trim()) {
      errorMessage.value = '请输入要解码的URL'
      isSuccess.value = false
      return
    }
    
    let result = encodedUrl.value
    
    // 根据编码类型选择解码方法
    for (let i = 0; i < encodeLevel.value; i++) {
      if (encodeType.value === 'component') {
        result = decodeURIComponent(result)
      } else {
        result = decodeURI(result)
      }
    }
    
    decodedUrl.value = result
    errorMessage.value = `URL解码成功 ✓ (${encodeType.value === 'component' ? 'Component' : 'Full'}, ${encodeLevel.value}次)`
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `URL解码失败: ${(error as Error).message}`
    isSuccess.value = false
    decodedUrl.value = ''
  }
}

// 自动检测并解码
function autoDecodeUrl() {
  try {
    if (!encodedUrl.value.trim()) {
      errorMessage.value = '请输入要解码的URL'
      isSuccess.value = false
      return
    }
    
    let result = encodedUrl.value
    let decodeCount = 0
    const maxDecodes = 10 // 防止无限循环
    
    // 持续解码直到不再变化或达到最大次数
    while (decodeCount < maxDecodes) {
      let decoded
      try {
        // 尝试两种解码方式
        const componentDecoded = decodeURIComponent(result)
        const uriDecoded = decodeURI(result)
        
        // 选择变化更大的解码结果
        if (componentDecoded !== result) {
          decoded = componentDecoded
        } else if (uriDecoded !== result) {
          decoded = uriDecoded
        } else {
          break // 没有变化，停止解码
        }
        
        if (decoded === result) {
          break // 解码后没有变化，停止
        }
        
        result = decoded
        decodeCount++
      } catch {
        break // 解码出错，停止
      }
    }
    
    decodedUrl.value = result
    errorMessage.value = `自动解码成功 ✓ (解码${decodeCount}次)`
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `自动解码失败: ${(error as Error).message}`
    isSuccess.value = false
    decodedUrl.value = ''
  }
}

// 解析URL组件
function parseUrl() {
  try {
    const urlToParse = decodedUrl.value || originalUrl.value
    if (!urlToParse.trim()) {
      errorMessage.value = '请输入要解析的URL'
      isSuccess.value = false
      return
    }
    
    const url = new URL(urlToParse)
    
    const components = {
      protocol: url.protocol,
      hostname: url.hostname,
      port: url.port,
      pathname: url.pathname,
      search: url.search,
      hash: url.hash,
      origin: url.origin,
      host: url.host
    }
    
    // 解析查询参数
    const params: Record<string, string> = {}
    url.searchParams.forEach((value, key) => {
      params[key] = value
    })
    
    const result = {
      components,
      searchParams: params
    }
    
    // 显示解析结果
    const resultText = JSON.stringify(result, null, 2)
    decodedUrl.value = resultText
    errorMessage.value = 'URL解析成功 ✓'
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `URL解析失败: ${(error as Error).message}`
    isSuccess.value = false
  }
}

// 复制到剪贴板
function copyToClipboard(text: string, type: string) {
  if (text) {
    navigator.clipboard.writeText(text).then(() => {
      errorMessage.value = `${type}已复制到剪贴板 ✓`
      isSuccess.value = true
    })
  }
}

// 清空所有
function clearAll() {
  originalUrl.value = ''
  encodedUrl.value = ''
  decodedUrl.value = ''
  errorMessage.value = ''
  isSuccess.value = false
}

// 交换编码解码文本
function swapTexts() {
  const temp = originalUrl.value
  originalUrl.value = decodedUrl.value
  decodedUrl.value = temp
  
  encodedUrl.value = ''
  errorMessage.value = '文本已交换 ✓'
  isSuccess.value = true
}

// 加载示例
function loadSample() {
  originalUrl.value = 'https://example.com/search?q=Hello World&lang=zh-CN&type=web#section1'
  errorMessage.value = '示例URL已加载 ✓'
  isSuccess.value = true
}

// 加载复杂示例
function loadComplexSample() {
  originalUrl.value = 'https://example.com/api/v1/users?name=张三&email=test@example.com&tags[]=前端&tags[]=Vue.js&callback=jsonp_callback_123&timestamp=' + Date.now()
  errorMessage.value = '复杂示例URL已加载 ✓'
  isSuccess.value = true
}

// 生成测试URL
function generateTestUrl() {
  const specialChars = '!@#$%^&*()_+-=[]{}|;:",./<>?`~'
  const chineseChars = '中文测试参数值'
  const spaces = 'hello world test'
  
  const testUrl = `https://test.example.com/path/to/resource?special=${specialChars}&chinese=${chineseChars}&spaces=${spaces}&number=12345&boolean=true&array[0]=item1&array[1]=item2#fragment-with-special-chars`
  
  originalUrl.value = testUrl
  errorMessage.value = '测试URL已生成 ✓'
  isSuccess.value = true
}

// 验证URL格式
function validateUrl(url: string): boolean {
  try {
    new URL(url)
    return true
  } catch {
    return false
  }
}

// 格式化显示URL
function formatUrl() {
  try {
    const urlToFormat = decodedUrl.value || originalUrl.value
    if (!urlToFormat.trim()) {
      errorMessage.value = '请输入要格式化的URL'
      isSuccess.value = false
      return
    }
    
    if (!validateUrl(urlToFormat)) {
      errorMessage.value = 'URL格式无效'
      isSuccess.value = false
      return
    }
    
    const url = new URL(urlToFormat)
    
    let formatted = `协议: ${url.protocol}\n`
    formatted += `主机: ${url.hostname}\n`
    if (url.port) formatted += `端口: ${url.port}\n`
    formatted += `路径: ${url.pathname}\n`
    
    if (url.search) {
      formatted += `\n查询参数:\n`
      url.searchParams.forEach((value, key) => {
        formatted += `  ${key} = ${value}\n`
      })
    }
    
    if (url.hash) {
      formatted += `\n锚点: ${url.hash}\n`
    }
    
    decodedUrl.value = formatted
    errorMessage.value = 'URL格式化成功 ✓'
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `URL格式化失败: ${(error as Error).message}`
    isSuccess.value = false
  }
}
</script>

<template>
  <div class="url-tool">
    <div class="config-section">
      <h3>URL编解码配置</h3>
      <div class="config-grid">
        <div class="config-item">
          <label>编码类型:</label>
          <select v-model="encodeType" class="config-select">
            <option value="component">encodeURIComponent (推荐)</option>
            <option value="full">encodeURI (完整URL)</option>
          </select>
        </div>
        
        <div class="config-item">
          <label>编码次数:</label>
          <select v-model="encodeLevel" class="config-select">
            <option :value="1">1次</option>
            <option :value="2">2次</option>
            <option :value="3">3次</option>
          </select>
        </div>
      </div>
      
      <div class="encoding-info">
        <h4>编码类型说明:</h4>
        <ul>
          <li><strong>encodeURIComponent:</strong> 编码所有特殊字符，适用于URL参数值</li>
          <li><strong>encodeURI:</strong> 保留URL结构字符，适用于完整URL</li>
        </ul>
      </div>
    </div>

    <div class="controls">
      <button class="btn btn-primary" @click="encodeUrl">🔒 编码</button>
      <button class="btn btn-primary" @click="decodeUrl">🔓 解码</button>
      <button class="btn btn-info" @click="autoDecodeUrl">🤖 自动解码</button>
      <button class="btn btn-secondary" @click="parseUrl">🔍 解析URL</button>
      <button class="btn btn-secondary" @click="formatUrl">📋 格式化</button>
      <button class="btn btn-info" @click="swapTexts">🔄 交换文本</button>
      <button class="btn btn-warning" @click="loadSample">📝 简单示例</button>
      <button class="btn btn-warning" @click="loadComplexSample">🔧 复杂示例</button>
      <button class="btn btn-warning" @click="generateTestUrl">🧪 测试URL</button>
      <button class="btn btn-danger" @click="clearAll">🗑️ 清空</button>
    </div>

    <div class="status" v-if="errorMessage" :class="{ 'error': !isSuccess, 'success': isSuccess }">
      {{ errorMessage }}
    </div>

    <div class="editor-container">
      <div class="editor-section">
        <h3>原始URL</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="originalUrl" 
            class="text-input"
            placeholder="请输入要编码的URL...\n\n示例:\nhttps://example.com/search?q=Hello World&lang=zh-CN\nhttps://test.com/api?name=张三&age=25"
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(originalUrl, '原始URL')"
            :disabled="!originalUrl"
          >
            📋
          </button>
        </div>
        <div class="url-validation" v-if="originalUrl">
          <span :class="{ 'valid': validateUrl(originalUrl), 'invalid': !validateUrl(originalUrl) }">
            {{ validateUrl(originalUrl) ? '✓ URL格式有效' : '✗ URL格式无效' }}
          </span>
        </div>
      </div>

      <div class="editor-section">
        <h3>编码后URL</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="encodedUrl" 
            class="text-output"
            placeholder="编码后的URL将显示在这里...\n\n可以手动输入已编码的URL进行解码"
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(encodedUrl, '编码URL')"
            :disabled="!encodedUrl"
          >
            📋
          </button>
        </div>
        <div class="encoding-stats" v-if="encodedUrl">
          <span>长度: {{ encodedUrl.length }} 字符</span>
        </div>
      </div>

      <div class="editor-section">
        <h3>解码结果</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="decodedUrl" 
            class="text-output"
            placeholder="解码后的URL或解析结果将显示在这里..."
            readonly
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(decodedUrl, '解码结果')"
            :disabled="!decodedUrl"
          >
            📋
          </button>
        </div>
        <div class="url-validation" v-if="decodedUrl && !decodedUrl.includes('{')"> 
          <span :class="{ 'valid': validateUrl(decodedUrl), 'invalid': !validateUrl(decodedUrl) }">
            {{ validateUrl(decodedUrl) ? '✓ URL格式有效' : '✗ URL格式无效' }}
          </span>
        </div>
      </div>
    </div>

    <div class="quick-tools">
      <h3>快捷工具</h3>
      <div class="quick-tools-grid">
        <div class="quick-tool">
          <h4>常见编码字符</h4>
          <div class="char-mapping">
            <div class="char-item">空格 → %20</div>
            <div class="char-item">& → %26</div>
            <div class="char-item">= → %3D</div>
            <div class="char-item">? → %3F</div>
            <div class="char-item"># → %23</div>
            <div class="char-item">+ → %2B</div>
            <div class="char-item">/ → %2F</div>
            <div class="char-item">: → %3A</div>
          </div>
        </div>
        
        <div class="quick-tool">
          <h4>中文字符示例</h4>
          <div class="char-mapping">
            <div class="char-item">中 → %E4%B8%AD</div>
            <div class="char-item">文 → %E6%96%87</div>
            <div class="char-item">测 → %E6%B5%8B</div>
            <div class="char-item">试 → %E8%AF%95</div>
          </div>
        </div>
        
        <div class="quick-tool">
          <h4>特殊字符示例</h4>
          <div class="char-mapping">
            <div class="char-item">@ → %40</div>
            <div class="char-item">! → %21</div>
            <div class="char-item">* → %2A</div>
            <div class="char-item">' → %27</div>
            <div class="char-item">( → %28</div>
            <div class="char-item">) → %29</div>
            <div class="char-item">; → %3B</div>
            <div class="char-item">, → %2C</div>
          </div>
        </div>
      </div>
    </div>

    <div class="help-section">
      <details>
        <summary>URL编解码说明</summary>
        <div class="help-content">
          <h4>URL编码的作用:</h4>
          <ul>
            <li><strong>安全传输:</strong> 确保URL中的特殊字符能正确传输</li>
            <li><strong>参数分离:</strong> 防止参数值中的特殊字符影响URL结构</li>
            <li><strong>国际化支持:</strong> 支持中文等非ASCII字符</li>
          </ul>
          <h4>编码方式对比:</h4>
          <ul>
            <li><strong>encodeURIComponent:</strong> 编码除字母数字和 -_.!~*'() 外的所有字符</li>
            <li><strong>encodeURI:</strong> 不编码 ;,/?:@&=+$# 等URL结构字符</li>
          </ul>
          <h4>使用场景:</h4>
          <ul>
            <li><strong>查询参数:</strong> 使用 encodeURIComponent 编码参数值</li>
            <li><strong>完整URL:</strong> 使用 encodeURI 编码整个URL</li>
            <li><strong>表单提交:</strong> 浏览器自动进行URL编码</li>
            <li><strong>API调用:</strong> 手动编码特殊字符参数</li>
          </ul>
          <h4>注意事项:</h4>
          <ul>
            <li>不要对已编码的URL重复编码</li>
            <li>解码时要使用对应的解码方法</li>
            <li>某些字符在不同上下文中编码规则不同</li>
          </ul>
        </div>
      </details>
    </div>
  </div>
</template>

<style scoped>
.url-tool {
  width: 100%;
}

.config-section {
  margin-bottom: 20px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.config-section h3 {
  margin: 0 0 15px 0;
  color: #fff;
  font-size: 1.1em;
}

.config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
  margin-bottom: 15px;
}

.config-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.config-item label {
  color: #ccc;
  font-size: 14px;
  font-weight: 500;
}

.config-select {
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  outline: none;
}

.config-select:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.encoding-info {
  margin-top: 15px;
  padding: 15px;
  background: rgba(0, 123, 255, 0.1);
  border-radius: 6px;
  border: 1px solid rgba(0, 123, 255, 0.3);
}

.encoding-info h4 {
  margin: 0 0 10px 0;
  color: #007bff;
  font-size: 1em;
}

.encoding-info ul {
  margin: 0;
  padding-left: 20px;
  color: #ccc;
}

.encoding-info li {
  margin-bottom: 5px;
  line-height: 1.4;
}

.encoding-info strong {
  color: #fff;
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s ease;
  color: #fff;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-sm {
  padding: 4px 8px;
  font-size: 12px;
}

.btn-primary {
  background: #007bff;
}

.btn-primary:hover:not(:disabled) {
  background: #0056b3;
}

.btn-secondary {
  background: #6c757d;
}

.btn-secondary:hover:not(:disabled) {
  background: #545b62;
}

.btn-success {
  background: #28a745;
}

.btn-success:hover:not(:disabled) {
  background: #1e7e34;
}

.btn-info {
  background: #17a2b8;
}

.btn-info:hover:not(:disabled) {
  background: #117a8b;
}

.btn-warning {
  background: #ffc107;
  color: #212529;
}

.btn-warning:hover:not(:disabled) {
  background: #e0a800;
}

.btn-danger {
  background: #dc3545;
}

.btn-danger:hover:not(:disabled) {
  background: #c82333;
}

.status {
  padding: 12px;
  border-radius: 6px;
  margin-bottom: 20px;
  font-weight: 500;
}

.status.error {
  background: rgba(220, 53, 69, 0.1);
  color: #dc3545;
  border: 1px solid rgba(220, 53, 69, 0.3);
}

.status.success {
  background: rgba(40, 167, 69, 0.1);
  color: #28a745;
  border: 1px solid rgba(40, 167, 69, 0.3);
}

.editor-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
  margin-bottom: 20px;
}

.editor-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.editor-section h3 {
  margin: 0;
  color: #fff;
  font-size: 1.1em;
}

.textarea-wrapper {
  position: relative;
  height: 200px;
}

.text-input,
.text-output {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  padding: 12px;
  color: #fff;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.5;
  resize: none;
  outline: none;
}

.text-output {
  background: rgba(0, 0, 0, 0.4);
}

.text-input:focus,
.text-output:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.text-input::placeholder,
.text-output::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
}

.url-validation {
  margin-top: 5px;
  font-size: 12px;
}

.url-validation .valid {
  color: #28a745;
}

.url-validation .invalid {
  color: #dc3545;
}

.encoding-stats {
  margin-top: 5px;
  font-size: 12px;
  color: #ccc;
}

.quick-tools {
  margin-bottom: 20px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.quick-tools h3 {
  margin: 0 0 15px 0;
  color: #fff;
  font-size: 1.1em;
}

.quick-tools-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

.quick-tool {
  padding: 15px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.quick-tool h4 {
  margin: 0 0 10px 0;
  color: #fff;
  font-size: 1em;
}

.char-mapping {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5px;
}

.char-item {
  padding: 4px 8px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 3px;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 12px;
  color: #ccc;
  text-align: center;
}

.help-section {
  margin-top: 20px;
}

.help-section details {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.help-section summary {
  padding: 12px 15px;
  cursor: pointer;
  color: #fff;
  font-weight: 500;
  user-select: none;
}

.help-section summary:hover {
  background: rgba(255, 255, 255, 0.05);
}

.help-content {
  padding: 15px;
  color: #ccc;
}

.help-content h4 {
  margin: 0 0 10px 0;
  color: #fff;
  font-size: 1em;
}

.help-content ul {
  margin: 0 0 15px 0;
  padding-left: 20px;
}

.help-content li {
  margin-bottom: 5px;
  line-height: 1.4;
}

.help-content strong {
  color: #fff;
}

@media (max-width: 768px) {
  .config-grid {
    grid-template-columns: 1fr;
  }
  
  .editor-container {
    grid-template-columns: 1fr;
  }
  
  .quick-tools-grid {
    grid-template-columns: 1fr;
  }
  
  .char-mapping {
    grid-template-columns: 1fr;
  }
  
  .controls {
    justify-content: center;
  }
}
</style>